package cn.tedu.charging.core;

import cn.tedu.charging.account.dao.cache.IUserCacheRepository;
import cn.tedu.charging.account.pojo.entity.User;
import cn.tedu.charging.account.pojo.vo.UserStandardVO;
import cn.tedu.charging.common.consts.HttpConsts;
import cn.tedu.charging.common.po.UserLoginInfoPO;
import cn.tedu.charging.web.JsonResult;
import cn.tedu.charging.web.ServiceCode;
import com.alibaba.fastjson.JSON;
import io.jsonwebtoken.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * 处理JWT的过滤器
 *
 * @author wyy
 * @version 1.0
 */
@Component
@Slf4j
public class JwtAuthorizationFilter extends OncePerRequestFilter implements HttpConsts {

    @Value("${charging.jwt.secret-key}")
    private String secretKey;

    @Autowired
    private IUserCacheRepository userCacheRepository;


    public JwtAuthorizationFilter() {
        log.info("创建过滤器对象：JwtAuthorizationFilter");
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        log.debug("处理JWT的过滤器开始处理当前请求……");
        String path = request.getRequestURI();
        // 如果请求的路径为/wxLogin，则直接调用下一个过滤器
        if (path.equals("/wxLogin")) {
            filterChain.doFilter(request, response);
            return;
        }
        // 尝试接收客户端的请求中携带的JWT数据
        // 业内惯用的做法是：客户端会将JWT放在请求头中名为Authorization的属性中
        String jwt = request.getHeader(HEADER_AUTHORIZATION);
        log.debug("客户端携带的JWT：{}", jwt);
        if (jwt == null || jwt.isEmpty()){
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            // TODO 能发返回后面的格式 “{ code: HttpServletResponse.SC_UNAUTHORIZED, message: ’未登录！‘ }”
            response.getWriter().write("未登录！");
            return;
        }

        // 从Redis中读取此JWT对应的数据
        UserLoginInfoPO loginInfo = userCacheRepository.getLoginInfo(jwt);
        // 判断Redis中是否存在此JWT相关数据
        if (loginInfo == null) {
            log.warn("在Redis中无此对应的信息，将直接放行，交由后续的组件进行处理");
            // filterChain.doFilter(request, response);
            response.getWriter().write("token过期或者不存在！");
            return;
        }

        // 尝试解析JWT数据
        log.debug("尝试解析JWT数据……");
        response.setContentType("application/json; charset=utf-8");
        Claims claims = null;
        try {
            claims = Jwts.parser()
                    .setSigningKey(secretKey)
                    .parseClaimsJws(jwt)
                    .getBody();
        } catch (ExpiredJwtException e) {
            log.warn("解析JWT时出现异常：ExpiredJwtException");
            String message = "操作失败，您的登录信息已经过期，请重新登录！";
            JsonResult jsonResult = JsonResult.fail(ServiceCode.ERR_JWT_EXPIRED, message);
            PrintWriter writer = response.getWriter();
            writer.println(JSON.toJSONString(jsonResult));
            writer.close();
            return;
        } catch (SignatureException e) {
            log.warn("解析JWT时出现异常：SignatureException");
            String message = "非法访问，你的本次操作已经被记录！";
            JsonResult jsonResult = JsonResult.fail(ServiceCode.ERR_JWT_SIGNATURE, message);
            PrintWriter writer = response.getWriter();
            writer.println(JSON.toJSONString(jsonResult));
            writer.close();
            return;
        } catch (MalformedJwtException e) {
            log.warn("解析JWT时出现异常：MalformedJwtException");
            String message = "非法访问，你的本次操作已经被记录！";
            JsonResult jsonResult = JsonResult.fail(ServiceCode.ERR_JWT_MALFORMED, message);
            PrintWriter writer = response.getWriter();
            writer.println(JSON.toJSONString(jsonResult));
            writer.close();
            return;
        }catch (Throwable e) {
            log.warn("解析JWT时出现异常：{}", e);
            String message = "服务器忙，请稍后再试！";
            JsonResult jsonResult = JsonResult.fail(ServiceCode.ERROR_UNKNOWN, message);
            PrintWriter writer = response.getWriter();
            writer.println(JSON.toJSONString(jsonResult));
            writer.close();
            return;
        }

        // 从解析结果中获取用户的信息
        Long id = claims.get("id", Long.class);
        log.debug("JWT中的用户id = {}", id);

        // 过滤器链继续执行，即：放行
        filterChain.doFilter(request, response);
    }
}
